﻿package kizzo.datastruct   
{		
	import flash.display.Sprite;
	import flash.filters.DropShadowFilter;
	import flash.geom.Point;
	import flash.text.TextField;
	import flash.events.MouseEvent;
	import flash.events.Event;
	import flash.text.TextFormat;
	import flash.utils.*;
	import flash.text.AntiAliasType;
	import flash.filters.GlowFilter;	
	
	public class Vertex
	{
		private var _status:int;
		private var _name:String;	
		
		private var index_edges:Array;
		private var name_edges:Array;
		
		private var index_in_edges:Array;
		private var name_in_edges:Array;
		
		internal var pt:Point;
		
		public static const NOT_VISITED:int = 0;
		public static const VISITED:int = 1;
		
		public var sprite:Sprite;
		private var vertex:Sprite;
		private var edges:Sprite;
		private var name_tf:TextField;
		
		private var graph:Graph;		
		private var int_hnd:int;		
		private var _path:Path;
		
		/**
		 * Creates a vertex.
		 * @param	graph The graph to which the vertex belongs.
		 * @param	name Name of the vertex. If this parameter is omitted an automatically generated name will be assigned.
		 * @param	pt This is the position of the graphical representation of the vertex in the parent sprite of the graph.
		 */
		public function Vertex(graph:Graph, name:String="", pt:Point = null) 
		{
			this._status = NOT_VISITED;
			this._name = name;
			this.index_edges = [];	
			this.name_edges = [];
			
			this.index_in_edges = [];	
			this.name_in_edges = [];			
			
			this.sprite = new Sprite();
			this.vertex = new Sprite();
			this.edges = new Sprite();
			
			this.graph = graph;
			
			if (pt == null)
			{
				var x:Number = Math.round(100 + Math.random() * 600);
				var y:Number = Math.round(100 + Math.random() * 400);				
				this.pt = new Point(x, y);
			}
			else
				this.pt = pt;
		}
		
		/**
		 * Returns the status of the vertex (visited/non-visited).
		 */
		public function get status():int
		{
			return _status;
		}

		/**
		 * Sets the status of a vertex.
		 */
		public function set status(status:int):void
		{
			this._status = status;
		}		
		
		
		public function get name():String
		{
			return _name;
		}
		
		
		public function set name(name:String):void
		{
			this._name = name;
		}
		
		
		public function addEdge(e:Edge):void
		{
			var name:String = e.end_vertex.name;
			if (this.name_edges[name])
			{
				trace ("Trying to add existing edge. Edge not added.");
				return;
			}
			if (e.end_vertex.name == e.start_vertex.name)
			{
				trace ("Looping edges not allowed. Edge not added.");
				return;
			}
			
			e.end_vertex.addInEdge(e);
			
			this.index_edges.push(e);
			this.name_edges[name] = e;
		}
		
		
		public function addInEdge(e:Edge):void
		{
			var name:String = e.start_vertex.name;
			if (this.name_in_edges[name])
			{
				trace ("Trying to add existing edge. Edge not added.");
				return;
			}
			
			this.index_in_edges.push(e);
			this.name_in_edges[name] = e;
		}		
		
		
		public function traceVertex():void
		{
			trace("\n\n--------------\nVertex:" + this._name);
			for (var i:uint = 0; i < this.index_edges.length; i++)
				this.index_edges[i].traceEdge();
		}
		
		
		public function draw():void
		{			
			vertex.graphics.beginFill(0xff3333, .8);
			vertex.graphics.drawCircle(0, 0, 9);
			vertex.graphics.endFill();			
						
			name_tf = new TextField();			
			name_tf.text = this._name;			
			var tf_format:TextFormat = new TextFormat("Tahoma", 9);
			name_tf.setTextFormat(tf_format);
			name_tf.x = 10;
			name_tf.y = - 10;
			name_tf.selectable = false;			
			sprite.addChild(name_tf);
			name_tf.mouseEnabled = false;
			//name_tf.filters = [new GlowFilter(0xffffff, .8, 2, 2, 4, 2)];
			
			
			if (this.sprite.stage == null)
				sprite.addEventListener(Event.ADDED_TO_STAGE, init_events);			
			
			sprite.x = this.pt.x;
			sprite.y = this.pt.y;
				
			for (var i:uint = 0; i < this.index_edges.length; i++)
			{
				this.index_edges[i].draw();
				edges.addChild(this.index_edges[i].sprite);
			}	
			sprite.addChildAt(vertex,0);
			sprite.addChild(edges);
			edges.mouseEnabled = false;
			edges.mouseChildren = false;
			sprite.mouseEnabled = false;
			
			//while (vertex.hitTestObject(graph.sprite))
			//	reposition();
			//sprite.filters = [new GlowFilter(0xffffff, .8, 4, 4, 6, 1)];
		}	
		
		
		private function init_events(e:Event):void
		{			
			vertex.addEventListener(MouseEvent.MOUSE_DOWN, function (e:Event):void { clearInterval(int_hnd); int_hnd = setInterval(move_update, 20); } );			
			vertex.stage.addEventListener(MouseEvent.MOUSE_UP, function ():void { clearInterval(int_hnd); } );
			
			vertex.buttonMode = true;
			//sprite.hitArea = vertex;
			//sprite.buttonMode = true;
		}
		
		
		private function reposition():void
		{
			var x:Number = Math.round(100 + Math.random() * 600);
			var y:Number = Math.round(100 + Math.random() * 400);				
			this.pt = new Point(x, y);
			this.sprite.x = this.pt.x;
			this.sprite.y = this.pt.y;
		}
		
		
		private function move_update():void
		{
			this.pt.x = this.sprite.x = this.sprite.stage.mouseX;
			this.pt.y = this.sprite.y = this.sprite.stage.mouseY;
			
			for (var i:uint = 0; i < this.index_edges.length; i++)
			{
				this.index_edges[i].draw();
			}
			
			for (i = 0; i < this.index_in_edges.length; i++)
			{
				this.index_in_edges[i].draw();
			}			
		}
		
		
		public function getEdgeIterator():ArrayIterator
		{
			return new ArrayIterator(this.index_edges);
		}
		
		
		public function hasEdgeTo(v:Vertex):Boolean
		{
			return Boolean(this.name_edges[v.name]);
		}
		
		public function set path(path:Path):void
		{
			this._path = path;			
		}
		
		public function get path():Path
		{
			return this._path;
		}
		
	}
	
}